#pragma once

//based on Herb Sutters GotW 102 -- http://herbsutter.com/gotw/_102/
//because variadic templates are not working yet I've made specializations for 0 - 10 arguments
//if you need more, start copy-pasting already!

#include "stdafx.h"

namespace std { //yah, this really belongs in std
	/*
	//As soon as variadic templates are working in msvc, this should be the correct way to implement it
	template <typename T, typename ...Args>
	std::unique_ptr<T> make_unique(Args&& ...args) {
		return std::unique_ptr<T>(new T(std::forward<Args>(args)...)));
	}
	*/

	template <typename T>
	std::unique_ptr<T> make_unique() {
		return std::unique_ptr<T>(new T());
	}

	template <typename T, typename A1>
	std::unique_ptr<T> make_unique(A1&& a1) {
		return std::unique_ptr<T>(new T(std::forward<A1>(a1)));
	}

	template <typename T, typename A1, typename A2>
	std::unique_ptr<T> make_unique(A1&& a1, A2&& a2) {
		return std::unique_ptr<T>(
			new T(
				std::forward<A1>(a1), 
				std::forward<A2>(a2)
			)
		);
	}

	template <typename T, typename A1, typename A2, typename A3>
	std::unique_ptr<T> make_unique(A1&& a1, A2&& a2, A3&& a3) {
		return std::unique_ptr<T>(
			new T(
				std::forward<A1>(a1), 
				std::forward<A2>(a2),
				std::forward<A3>(a3)
			)
		);
	}

	template <typename T, typename A1, typename A2, typename A3, typename A4>
	std::unique_ptr<T> make_unique(A1&& a1, A2&& a2, A3&& a3, A4&& a4) {
		return std::unique_ptr<T>(
			new T(
				std::forward<A1>(a1), 
				std::forward<A2>(a2),
				std::forward<A3>(a3),
				std::forward<A4>(a4)
			)
		);
	}

	template <typename T, typename A1, typename A2, typename A3, typename A4, typename A5>
	std::unique_ptr<T> make_unique(A1&& a1, A2&& a2, A3&& a3, A4&& a4, A5&& a5) {
		return std::unique_ptr<T>(
			new T(
				std::forward<A1>(a1), 
				std::forward<A2>(a2),
				std::forward<A3>(a3),
				std::forward<A4>(a4),
				std::forward<A5>(a5)
			)
		);
	}

	template <typename T, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6>
	std::unique_ptr<T> make_unique(A1&& a1, A2&& a2, A3&& a3, A4&& a4, A5&& a5, A6&& a6) {
		return std::unique_ptr<T>(
			new T(
				std::forward<A1>(a1), 
				std::forward<A2>(a2),
				std::forward<A3>(a3),
				std::forward<A4>(a4),
				std::forward<A5>(a5),
				std::forward<A6>(a6)
			)
		);
	}

	template <typename T, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7>
	std::unique_ptr<T> make_unique(A1&& a1, A2&& a2, A3&& a3, A4&& a4, A5&& a5, A6&& a6, A7&& a7) {
		return std::unique_ptr<T>(
			new T(
				std::forward<A1>(a1), 
				std::forward<A2>(a2),
				std::forward<A3>(a3),
				std::forward<A4>(a4),
				std::forward<A5>(a5),
				std::forward<A6>(a6),
				std::forward<A7>(a7)
			)
		);
	}

	template <typename T, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8>
	std::unique_ptr<T> make_unique(A1&& a1, A2&& a2, A3&& a3, A4&& a4, A5&& a5, A6&& a6, A7&& a7, A8&& a8) {
		return std::unique_ptr<T>(
			new T(
				std::forward<A1>(a1), 
				std::forward<A2>(a2),
				std::forward<A3>(a3),
				std::forward<A4>(a4),
				std::forward<A5>(a5),
				std::forward<A6>(a6),
				std::forward<A7>(a7),
				std::forward<A8>(a8)
			)
		);
	}

	template <typename T, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9>
	std::unique_ptr<T> make_unique(A1&& a1, A2&& a2, A3&& a3, A4&& a4, A5&& a5, A6&& a6, A7&& a7, A8&& a8, A9&& a9) {
		return std::unique_ptr<T>(
			new T(
				std::forward<A1>(a1), 
				std::forward<A2>(a2),
				std::forward<A3>(a3),
				std::forward<A4>(a4),
				std::forward<A5>(a5),
				std::forward<A6>(a6),
				std::forward<A7>(a7),
				std::forward<A8>(a8),
				std::forward<A9>(a9)
			)
		);
	}

	template <typename T, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10>
	std::unique_ptr<T> make_unique(A1&& a1, A2&& a2, A3&& a3, A4&& a4, A5&& a5, A6&& a6, A7&& a7, A8&& a8, A9&& a9, A10&& a10) {
		return std::unique_ptr<T>(
			new T(
				std::forward<A1>(a1), 
				std::forward<A2>(a2),
				std::forward<A3>(a3),
				std::forward<A4>(a4),
				std::forward<A5>(a5),
				std::forward<A6>(a6),
				std::forward<A7>(a7),
				std::forward<A8>(a8),
				std::forward<A9>(a9),
				std::forward<A10>(a10)
			)
		);
	}
}
